function [gBest,val_gBest,outcome]=CLPSO(mainHandle,popsize,dimension,xmax,xmin,vmax,vmin,maxiter,Func,FuncId,VisualSwitch)
%************************************************************************************************** 
%  CLPSO： Comprehensive Learning Particle Swarm Optimizer for Global Optimization of Multimodal Functions
%  We obtained the MATLAB source code from the authors
%  Date: 2014/11/14
%**************************************************************************************************

    fun = Func;

    D = dimension;
    lu = [xmin * ones(1, D); xmax * ones(1, D)];
    Xmin = lu(1,:);
    Xmax = lu(2,:);  

    rand('seed', sum(100 * clock)); 

    % parameters setting for CLPSO
    maxFES = 1e4*D;
    maxGEN = maxiter; 
    iwt = 0.9 - (1 : maxGEN) * (0.7 / maxGEN);
    c = 1.49445;
    
    % Initialize the main population
    X = repmat(Xmin, popsize, 1) + rand(popsize,D) .* (repmat(Xmax-Xmin, popsize, 1));
    for i = 1:popsize
        val_X(i,:) = fun(X(i,:)',FuncId);  
    end
    pBest = X; 
    val_pBest = val_X;  
    [~,indexG] = min(val_pBest);
    gBest = pBest(indexG,:); 
    val_gBest = val_pBest(indexG,:);    
    Vmax = (Xmax - Xmin)*0.2;  Vmin = -Vmax;    
    V = repmat(Vmin,popsize,1) + rand(popsize,D).*repmat(Vmax-Vmin,popsize,1);
    
    % Learning Probability Pc
    t = 0 : 1/(popsize-1):1;
    t = 5.*t;
    Pc = 0.0+(0.5-0.0).*(exp(t)-exp(t(1)))./(exp(t(popsize))-exp(t(1)));
    
    % Refreshing Gap
    gapm = 5; stay_num = zeros(1,popsize); 
    for i = 1:popsize
        pBest_ind(i,:) = LearnIndex_CLPSO(val_pBest,popsize,D,i,Pc(i));
    end 
             
    FES = popsize; GEN = 1;  
    outcome = [val_gBest*ones((FES),1)];  % record the best results

    while   FES < maxFES  

            for i = 1:popsize
                
                % update exemplar index
                if stay_num(i)>gapm   
                    pBest_ind(i,:) = LearnIndex_CLPSO(val_pBest,popsize,D,i,Pc(i));
                    stay_num(i) = 0;
                end 

                %  Compehensive Learning Strategy       
                for  j=1:D
                    pBest_f(i,j) = pBest(pBest_ind(i,j),j);  
                end  
                V(i,:) = iwt(GEN)*V(i,:) + c*rand(1,D).*(pBest_f(i,:)-X(i,:));  % update velocity
                V(i,:) = boundary_repair(V(i,:),Vmin,Vmax,'absorb');   
                X(i,:) = X(i,:)+V(i,:);    % update position

                if all(X(i,:)<=Xmax) & all(X(i,:)>=Xmin)  % X(i,:) is feasible
                    val = (fun(X(i,:)',FuncId))'; 
                    FES = FES+1;
                    if val<val_pBest(i)    % update pBest
                        pBest(i,:) = X(i,:);  val_pBest(i) = val;
                        stay_num(i) = 0;
                    else
                        stay_num(i) = stay_num(i)+1;
                    end 
                end 

            end  

            [~,indexG] = min(val_pBest);
            gBest = pBest(indexG,:); val_gBest = val_pBest(indexG,:);   

            FES0 = length(outcome);
            outcome = [outcome; val_gBest*ones((FES-FES0),1)];

            if mod(FES,1e4)<41
                fprintf("CLPSO 第%d次评价，最佳适应度 = %e\n",FES,val_gBest);
            end
            
            if FES >= maxFES
                break;
            end
            GEN = GEN+1;
            if (GEN == maxGEN) && (FES < maxFES)
                GEN = GEN-1;
            end 

                             
    end
if FES<maxFES
    outcome(FES+1:maxFES)=val_gBest;
else
    if FES>maxFES
        outcome(maxFES+1:end)=[];
    end
end       
 
end



function  pBest_ind = LearnIndex_CLPSO(pfit,popsize,D,i,Pci)
%  exemplar index

for j = 1:D
    if rand<Pci
        ind1 = randi(popsize);
        while ind1==i, ind1 = randi(popsize);  end
        ind2 = randi(popsize); 
        while ind2==i||ind2==ind1, ind2 = randi(popsize);  end
        if pfit(ind1)<pfit(ind2)
            pBest_ind(j) = ind1;
        else
            pBest_ind(j) = ind2;
        end 
    else
        pBest_ind(j) = i;
    end 
end

if all(pBest_ind==i)    
    ind = randi(popsize);
    while ind==i, ind = randi(popsize);  end
    pBest_ind(randi(D)) = ind; 
end
end

function u = boundary_repair(v,low,up,str)

[NP, D] = size(v);   
u = v; 
llow = repmat(low,NP,1);
uup  = repmat(up,NP,1);

if strcmp(str,'absorb')
    index1 = (u>uup);
    u(index1) = uup(index1); 
    index2 = (u<llow);
    u(index2) = llow(index2); 
end
   

if strcmp(str,'random')
    index1 = (u>uup)|(u<llow);
    rr = rand(size(u));
    u(index1) = llow(index1) + rr(index1).*(uup(index1)-llow(index1));  
end


if strcmp(str,'reflect')
    index1 = (u>uup);
    u(index1) = max( 2*uup(index1)-u(index1), llow(index1) );
    index2 = (u<llow);
    u(index2) = min( 2*llow(index2)-u(index2), uup(index2) );
end
end